#include <time.h>
#include "rte_rtc.h"
#include "delay.h"
#include <stm32f10x.h>
#include "global.h"

static RtcClockSource RtcType = UNKNOW;
static  vu16 AllBkp[16];

/*******************************************************************************
* Function Name  : Time_ConvCalendarToUnix(struct tm t)
* Description    : 写入RTC时钟当前时间
* Input          : struct tm t
* Output         : None
* Return         : time_t
*******************************************************************************/
time_t Time_ConvCalendarToUnix(struct tm t)
{
    t.tm_year -= 1900;  //外部tm结构体存储的年份为2008格式
    //而time.h中定义的年份格式为1900年开始的年份
    //所以，在日期转换时要考虑到这个因素。
    return mktime(&t);
}
/*******************************************************************************
* Function Name  : Time_ConvUnixToCalendar(time_t t)
* Description    : 转换UNIX时间戳为日历时间
* Input          : uint32_t t  当前时间的UNIX时间戳
* Output         : None
* Return         : struct tm
*******************************************************************************/
struct tm Time_ConvUnixToCalendar(time_t t)
{
    struct tm* t_tm;
    t_tm = localtime(&t);
    t_tm->tm_year += 1900;  //localtime转换结果的tm_year是相对值，需要转成绝对值
    return *t_tm;
}


/*******************************************************************************
* Function Name  : Time_SetUnixTime()
* Description    : 将给定的Unix时间戳写入RTC
* Input          : time_t t
* Output         : None
* Return         : None
*******************************************************************************/
void Time_SetUnixTime(time_t t)
{
    if (RtcType == UNKNOW)
    {
        return;
    }

    RTC_WaitForLastTask();
    RTC_SetCounter((uint32_t)t);
    RTC_WaitForLastTask();
    return;
}

/*******************************************************************************
* Function Name  : Time_SetCalendarTime()
* Description    : 将给定的Calendar格式时间转换成UNIX时间戳写入RTC
* Input          : struct tm t
* Output         : None
* Return         : None
*******************************************************************************/
void Time_SetCalendarTime(struct tm t)
{
    Time_SetUnixTime(Time_ConvCalendarToUnix(t));
    return;
}


void ReadAllBkp()
{
    AllBkp[0] = BKP_ReadBackupRegister(BKP_DR1);
    AllBkp[1] = BKP_ReadBackupRegister(BKP_DR2);
    AllBkp[2] = BKP_ReadBackupRegister(BKP_DR3);
    AllBkp[3] = BKP_ReadBackupRegister(BKP_DR4);
    AllBkp[4] = BKP_ReadBackupRegister(BKP_DR5);
    AllBkp[5] = BKP_ReadBackupRegister(BKP_DR6);
    AllBkp[6] = BKP_ReadBackupRegister(BKP_DR7);
    AllBkp[7] = BKP_ReadBackupRegister(BKP_DR8);
    AllBkp[8] = BKP_ReadBackupRegister(BKP_DR9);
    AllBkp[9] = BKP_ReadBackupRegister(BKP_DR10);
    AllBkp[10] = BKP_ReadBackupRegister(BKP_DR11);
    AllBkp[11] = BKP_ReadBackupRegister(BKP_DR12);
    AllBkp[12] = BKP_ReadBackupRegister(BKP_DR13);
    AllBkp[13] = BKP_ReadBackupRegister(BKP_DR14);
    AllBkp[14] = BKP_ReadBackupRegister(BKP_DR15);
    AllBkp[15] = BKP_ReadBackupRegister(BKP_DR16);
}



void WriteAllBkp()
{
    BKP_WriteBackupRegister(BKP_DR1, AllBkp[0]);
    BKP_WriteBackupRegister(BKP_DR2, AllBkp[1]);
    BKP_WriteBackupRegister(BKP_DR3, AllBkp[2]);
    BKP_WriteBackupRegister(BKP_DR4, AllBkp[3]);
    BKP_WriteBackupRegister(BKP_DR5, AllBkp[4]);
    BKP_WriteBackupRegister(BKP_DR6, AllBkp[5]);
    BKP_WriteBackupRegister(BKP_DR7, AllBkp[6]);
    BKP_WriteBackupRegister(BKP_DR8, AllBkp[7]);
    BKP_WriteBackupRegister(BKP_DR9, AllBkp[8]);
    BKP_WriteBackupRegister(BKP_DR10, AllBkp[9]);
    BKP_WriteBackupRegister(BKP_DR11, AllBkp[10]);
    BKP_WriteBackupRegister(BKP_DR12, AllBkp[11]);
    BKP_WriteBackupRegister(BKP_DR13, AllBkp[12]);
    BKP_WriteBackupRegister(BKP_DR14, AllBkp[13]);
    BKP_WriteBackupRegister(BKP_DR15, AllBkp[14]);
    BKP_WriteBackupRegister(BKP_DR16, AllBkp[15]);
}

void RTC_HSE_Configuration(void)
{

    //启用PWR和BKP的时钟（from APB1）
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    //后备域解锁
    PWR_BackupAccessCmd(ENABLE);

    //备份寄存器模块复位
    BKP_DeInit();

    //RTC时钟源配置成HSE/128
    RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);

    //RTC开启
    RCC_RTCCLKCmd(ENABLE);

    //开启后需要等待APB1时钟与RTC时钟同步，才能读写寄存器
    RTC_WaitForSynchro();

    //读写寄存器前，要确定上一个操作已经结束
    RTC_WaitForLastTask();

    //设置RTC分频器，使RTC时钟为1Hz
    //RTC period = RTCCLK/RTC_PR = (8MHz)/128=62500

    RTC_SetPrescaler(62499);

    //等待寄存器写入完成
    RTC_WaitForLastTask();

    //使能秒中断
    RTC_ITConfig(RTC_IT_SEC, DISABLE);

    //等待写入完成
    RTC_WaitForLastTask();
    RtcType = HSEDIV128;

    return;
}


void RTC_LSE_Configuration(void)
{
    uint8_t i = 0;
    //启用PWR和BKP的时钟（from APB1）
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    //后备域解锁
    PWR_BackupAccessCmd(ENABLE);

    //备份寄存器模块复位
    BKP_DeInit();
    //外部32.768K其哟偶那个
    RCC_LSEConfig(RCC_LSE_ON);

    for (i = 0; i < 50; i++)
    {

        if (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != RESET)
        {
            break;
        }

        delay_ms(100);
    }

    /*如果2S内LSE还不稳定则配置HSE作为RTC时钟源！
    这样在断电情况下，RTC时钟停止运行，每次上电时间为上次断电时间。*/
    if (i >= 50)
    {
        RTC_HSE_Configuration();
        return;
    }

    //RTC时钟源配置成LSE（外部32.768K）
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

    //RTC开启
    RCC_RTCCLKCmd(ENABLE);
    //开启后需要等待APB1时钟与RTC时钟同步，才能读写寄存器
    RTC_WaitForSynchro();
    //读写寄存器前，要确定上一个操作已经结束
    RTC_WaitForLastTask();
    //设置RTC分频器，使RTC时钟为1Hz
    //RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1)

    RTC_SetPrescaler(32767);

    //等待寄存器写入完成
    RTC_WaitForLastTask();

    //使能秒中断
    RTC_ITConfig(RTC_IT_SEC, ENABLE);

    //等待写入完成
    RTC_WaitForLastTask();

    RtcType = LSE;

    return;
}


void rtc_init(void)
{
    struct tm DefaultTime;
    uint8_t i = 0;
    uint32_t TempTime = 0;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    //我们在BKP的后备寄存器1中，存了一个特殊字符0xA5A5
    //第一次上电或后备电源掉电后，该寄存器数据丢失，
    //表明RTC数据丢失，需要重新配置
    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
    {
        //重新配置RTC
        RTC_LSE_Configuration();

        if (RtcType == UNKNOW)
        {
            return;
        }
        //配置完成后，向后备寄存器中写特殊字符0xA5A5
        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);

        //load default time
        DefaultTime.tm_year = 2015;
        DefaultTime.tm_mon = 8;
        DefaultTime.tm_mday = 1;

        DefaultTime.tm_hour = 8;
        DefaultTime.tm_min = 0;
        DefaultTime.tm_sec = 0;

        Time_SetCalendarTime(DefaultTime);
    }
    else
    {
        //若后备寄存器没有掉电，则无需重新配置RTC
        //这里我们可以利用RCC_GetFlagStatus()函数查看本次复位类型
        if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
        {
            //这是上电复位
        }
        else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
        {
            //这是外部RST管脚复位
        }

        //清除RCC中复位标志
        if ((RCC->BDCR & 0x300) == RCC_RTCCLKSource_LSE) //检测RTC时钟源，如果为LSE,设置标志
        {
            RtcType = LSE;
        }
        else if ((RCC->BDCR & 0x300) == RCC_RTCCLKSource_HSE_Div128) //如果HSE ，尝试配置LSE,如果失败将返回HSE
        {
            ReadAllBkp();
            TempTime = RTC_GetCounter();
            RTC_LSE_Configuration();
            Time_SetUnixTime(TempTime);
            WriteAllBkp();
        }
        else
        {
            RtcType = UNKNOW;
        }
        RCC_ClearFlag();

        //虽然RTC模块不需要重新配置，且掉电后依靠后备电池依然运行
        RCC_RTCCLKCmd(ENABLE);

        //等待RTC时钟与APB1时钟同步
        RTC_WaitForSynchro();
        /* Clear RSF flag */
        //        RTC->CRL &= ( uint16_t )~RTC_FLAG_RSF;

        for (i = 0; i < 50; i++)
        {
            if ((RTC->CRL & RTC_FLAG_RSF) != (uint16_t)RESET)
            {
                break;
            }
            delay_ms(100);
        }
        if (i >= 50)
        {
            ReadAllBkp();
            TempTime = RTC_GetCounter();
            RTC_HSE_Configuration();//后备寄存器0xA3A3仍然存在时，RTC和APB1时钟2S内不能同步，将视LSE失效，同样配置HSE作为RTC时钟源
            Time_SetUnixTime(TempTime);
            WriteAllBkp();
            return;
        }
        RTC_ITConfig(RTC_IT_SEC, ENABLE);       //使能秒中断
        //        RTC_WaitForLastTask();    //等待操作完成
        uint32_t timeout = 0xffff;
        while (((RTC->CRL & RTC_FLAG_RTOFF) == (uint16_t)RESET) && timeout--)
        {
        }
    }

    RCC_ClearFlag();

#ifdef RTCClockOutput_Enable
    /* Enable PWR and BKP clocks */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);


    /* Allow access to BKP Domain */
    PWR_BackupAccessCmd(ENABLE);

    /* Disable the Tamper Pin */
    BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper
                                     UART1_String("0-1!\r\n");
                                     functionality must be disabled */

                                     /* Enable RTC Clock Output on Tamper Pin */
    BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);

#endif

    return;
}


/*
**设置RTC时间
*/
void rtc_settime(struct tm* NowTime)
{
    Time_SetCalendarTime(*NowTime);
}
/*
**获取RTC时间
*/
uint8_t rtc_gettime(struct tm* NowTime)
{
    time_t t_t;

    t_t = (time_t)RTC_GetCounter();
    *NowTime = Time_ConvUnixToCalendar(t_t);
    NowTime->tm_mon++;
    return 1;
}



uint16_t DateTimeToMin(uint8_t Day, uint8_t Hour, uint8_t Min)
{
    return((uint16_t)Day * 1440 + (uint16_t)Hour * 60 + (uint16_t)Min);
}

/**************************************************************************
函数名称: ShutDownTimeSave
功能描述: 掉电时间保存
输入参数: 无
输出参数: 无
**************************************************************************/
void ShutDownTimeSave(struct tm* NoTime)
{
    /*BKP_DR1被RTC占用BKP_DR2-BKP_DR9被vin占用*/
    BKP_WriteBackupRegister(BKP_DR10, DateTimeToMin((uint8_t)NoTime->tm_mday, (uint8_t)NoTime->tm_hour, (uint8_t)NoTime->tm_min));
}
/**************************************************************************
函数名称: ShutDownTimeRead
功能描述: 读取掉电时间
输入参数: 无
输出参数: 无
**************************************************************************/
uint16_t ShutDownTimeRead(void)
{
    /*BKP_DR1被RTC占用BKP_DR2-BKP_DR9被vin占用*/
    return  BKP_ReadBackupRegister(BKP_DR10);
}



